\chapter{CRE2正则库基础}

CRE2的完整使用说明可参阅%
\url{https://marcomaggi.github.io/docs/cre2.html/type-index.html#SEC_Contents}，%
其相关示例代码在源代码仓库的\texttt{tests}子文件夹中。

在此，仅对CRE2的示例代码进行了简单整理和翻译，并添加了输出编译结果、输出匹配
结果等操作。同时，为节约篇幅，删除了原示例中部分判断代码。

\begin{note}
  \begin{enumerate}
    \item RE2不支持分组的反向引用语法。
    \item 代码的构建需要\enquote{C99}语法支持
  \end{enumerate}
\end{note}

\section{通用匹配}

可以分别使用\cinline{cre2_match()}和\cinline{cre2_easy_match()}函数实现常规的
正则匹配。

\subsection{用cre2\_match()函数实现匹配}

\cinline{cre2_match()}的函数原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    int cre2_match (const cre2_regexp_t * rex,
                    const char * text, int text_len,
                    int start_pos, int end_pos,
                    cre2_anchor_t anchor,
                    cre2_string_t * match, int nmatch);
  \end{ccode}
\end{minipage}

该函数返回1表示匹配成功，匹配失败则返回0。

形参：
\begin{description}
  \item \cinline{tex}: 指向编译后正则缓存的指针；
  \item \cinline{text}: 指向待匹配字符串的指针；
  \item \cinline{text_len}: 待匹配字符串长度；
  \item \cinline{start_pos}: 匹配开始位置(包含起始位置的字符)；
  \item \cinline{end_pos}: 匹配结束位置(不包含结束位置的字符)；
  \item \cinline{anchor}: 匹配锚点标志，可以有3种选择:
    \begin{itemize}
      \item \cinline{CRE2_UNANCHORED}；
      \item \cinline{CRE2_ANCHOR_START}；
      \item \cinline{CRE2_ANCHOR_BOTH}。
    \end{itemize}
  \item \cinline{match}: 指向匹配寄存器指针；
  \item \cinline{nmatch}: 匹配寄存器元素个数(正则表达式分组个数，包括整体正则表达式group 0)。
\end{description}

如果仅需要检查是否匹配成功，则可以为形参\cinline{match}提供\cinline{NULL}实参，%
为形参\cinline{nmatch}提供\cinline{0}实参。

\cinline{match}匹配寄存器数组的第一个元素(索引0)是整个正则表达式的匹配结果，
第二个元素(索引1)是第一个正则表达式小括号分组的匹配结果，依次类推。

使用\cinline{cre2_match()}函数实现匹配的示例如代码\ref{code-cre2-match}所示。

\cvfile[label=code-cre2-match]{用编译后的正则表达式实现匹配}%
  {google-cre2/codes/tests/01test-matching.c}

\subsection{用cre2\_easy\_match()函数实现匹配}

\cinline{cre2_easy_match()}的函数原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    int cre2_easy_match (const char * pattern, int pattern_len,
                         const char * text, int text_len,
                         cre2_string_t * match, int nmatch);
  \end{ccode}
\end{minipage}

该函数返回1表示匹配成功，匹配失败则返回0。

形参：
\begin{description}
  \item \cinline{pattern}: 指向正则表达式字符串的指针；
  \item \cinline{pattern_len}: 指向正则表达式字符串的指针；
  \item \cinline{text}: 指向待匹配字符串的指针；
  \item \cinline{text_len}: 待匹配字符串长度；
  \item \cinline{match}: 指向匹配寄存器指针；
  \item \cinline{nmatch}: 匹配寄存器元素个数(正则表达式分组个数，包括整体正则表达式group 0)。
\end{description}

该函数与\cinline{cre2_match()}函数的功能类似，但无需提前编译正则表达式。当然，
这会降低匹配速度。同时，它执行的是无锚点全文匹配。

显然，由于正则表达式没有进行编译，因此，无法为其指定正则表达式语法选项。

使用\cinline{cre2_easy_match()}函数实现匹配的示例如代码\ref{code-cre2-easy-match}所示。

\cvfile[label=code-cre2-easy-match]{直接使用正则表达式实现正则匹配}%
  {google-cre2/codes/tests/02test-easy-matching.c}

\section{其它匹配函数}

其它匹配函数都具备以下特征：
\begin{itemize}
  \item 如果匹配则返回1，不匹配则返回0。
  \item 如果正则表达式无效，则返回0。因此，无法直接通过返回值区分匹配失败和
      正则表达式错误。为此，需要通过输出的错误信息进行区分(可以输出到\cinline{stderr})。
  \item 正则表达式中小括号分组的匹配结果保存在长度为\cinline{nmatch}的%
      \cinline{match}数组中，数组的长度可以是0，也可以是小括号分组数量，但这些
      函数未将整个正则表达式视为默认分组，如果需要记录整体匹配信息，则需要在
      整个正则表达式两端添加小括号以构成分组。如果 \cinline{nmatch} 的值大于
      正则表达式中小括号分组数量，则函数返回0。
  \item 如果仅需要检查是否成功匹配，则可以使用\cinline{NULL}作为形参%
      \cinline{match}的实参，用\cinline{0}作为形参\cinline{nmatch}的实参。
  \item \cinline{match}数组的第一个元素(索引0)表示第一个小括号分组，第二个元素
      (索引1)表示第二个小括号分组，依次类推。
\end{itemize}

在以下函数中，无\enquote{\cinline{_re}}后缀的函数表示直接使用未编译的
\enquote{\cinline{pattern}}正则表达式字符串进行匹配，而有\enquote{\cinline{_re}}后缀的
函数表示使用编译过的\enquote{\cinline{rex}}正则对象进行匹配。

\subsection{完整匹配}

如果需要完整匹配，则可以使用\cinline{cre2_full_match()}或%
\cinline{cre2_full_match_re()}函数实现，其原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    int cre2_full_match(const char * pattern, const cre2_string_t * text,
                        cre2_string_t * match, int nmatch);
    int cre2_full_match_re(cre2_regexp_t * rex, const cre2_string_t * text,
                           cre2_string_t * match, int nmatch);
  \end{ccode}
\end{minipage}

完整匹配实例如代码\ref{code-cre2-full-match}所示。

\cvfile[label=code-cre2-full-match]{完整匹配}
  {google-cre2/codes/tests/03test-full-match.c}

\subsection{部分匹配}

如果需要部分匹配，则可以使用\cinline{cre2_partial_match()}或%
\cinline{cre2_partial_match_re()} 函数实现，其原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    int cre2_partial_match(const char * pattern, const cre2_string_t * text,
                           cre2_string_t * match, int nmatch);
    int cre2_partial_match_re(cre2_regexp_t * rex, const cre2_string_t * text,
                              cre2_string_t * match, int nmatch);
  \end{ccode}
\end{minipage}

部分匹配的实例如代码\ref{code-cre2-partial-match}所示。

\cvfile[label=code-cre2-partial-match]{部分匹配}%
  {google-cre2/codes/tests/04test-partial-match.c}

\subsection{剔除匹配}

如果需要剔除匹配，则可以使用\cinline{cre2_consume()}或%
\cinline{cre2_consume_re()} 函数实现，其函数原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    int cre2_consume(const char * pattern, cre2_string_t * text,
                     cre2_string_t * match, int nmatch);
    int cre2_consume_re(cre2_regexp_t * rex, cre2_string_t * text,
                        cre2_string_t * match, int nmatch);
  \end{ccode}
\end{minipage}

完成剔除匹配后，被匹配字符串\cinline{text}会定位于匹配结果之后的字符(剔除
匹配过的字符)。如：用\cinline{abc}正则表达式匹配\cinline{abcDEF}后，
\cinline{text}会指向\cinline{DEF}。

剔除匹配实例如代码\ref{code-cre2-consume-match}所示。

\cvfile[label=code-cre2-consume-match]{剔除匹配}%
  {google-cre2/codes/tests/05test-consume-match.c}

\subsection{查找并剔除匹配}

可以使用\cinline{cre2_find_and_consume()} 或%
\cinline{cre2_find_and_consume_re()} 函数实现，其函数原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    int cre2_find_and_consume(const char * pattern, cre2_string_t * text,
                              cre2_string_t * match, int nmatch);
    int cre2_find_and_consume_re(cre2_regexp_t * rex, cre2_string_t * text,
                                 cre2_string_t * match, int nmatch);
  \end{ccode}
\end{minipage}

完成查找并剔除匹配后，被匹配字符串\cinline{text}会定位于匹配结果之后的字符(剔除
匹配过的字符)。如：用\cinline{DEF}正则表达式匹配\cinline{abcDEFghi}后，%
\cinline{text}会越过前导\cinline{abc}字符指向\cinline{ghi}。

查找并剔除匹配实例如代码\ref{code-cre2-find-consume-match}所示。

\cvfile[label=code-cre2-find-consume-match]{查找剔除匹配}%
  {google-cre2/codes/tests/06test-find-and-consume-match.c}

\section{匹配并替换函数}

可以使用\cinline{cre2_replace()} 或\cinline{cre2_replace_re()} 函数实现
替换第一个匹配项，用 \cinline{cre2_global_replace()} 或 \cinline{cre2_global_replace_re()} %
函数实现替换所有匹配项，用 \cinline{cre2_extract()} 或 \cinline{cre2_extract_re()} %
函数实现提取匹配项。其函数原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    cre2_decl int cre2_replace(const char * pattern,
                       cre2_string_t * text_and_target,
                       cre2_string_t * rewrite);
    cre2_decl int cre2_replace_re(cre2_regexp_t * rex,
                       cre2_string_t * text_and_target,
                       cre2_string_t * rewrite);
    cre2_decl int cre2_global_replace(const char * pattern,
                       cre2_string_t * text_and_target,
                       cre2_string_t * rewrite);
    cre2_decl int cre2_global_replace_re(cre2_regexp_t * rex,
                       cre2_string_t * text_and_target,
                       cre2_string_t * rewrite);
  \end{ccode}
\end{minipage}

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    cre2_decl int cre2_extract(const char * pattern,
                       cre2_string_t * text,
                       cre2_string_t * rewrite,
                       cre2_string_t * target);
    cre2_decl int cre2_extract_re(cre2_regexp_t * rex,
                       cre2_string_t * text,
                       cre2_string_t * rewrite,
                       cre2_string_t * target);
  \end{ccode}
\end{minipage}

在替换或提取中，可以使用\verb|\1|--\verb|\9|引用正则
表达式中小括号分组的子表达式。

% 这些函数中，不带\enquote{\cinline{_re}}后缀的函数直接使用
% 未编译的\enquote{\cinline{pattern}}正则表达式字符串实现，带\enquote{\cinline{_re}}%
% 后缀的函数使用编译后的\enquote{\cinline{rex}}正则对象实现。

匹配并替换实例如代码\ref{code-cre2-replace-match}所示。

\cvfile[label=code-cre2-replace-match]{匹配并替换}%
  {google-cre2/codes/tests/07test-replace.c}

\section{正则表达式集合匹配}

可以使用正则表达式集合实现正则匹配，也就是多模匹配，相关函数原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    cre2_decl cre2_set *cre2_set_new(cre2_options_t *opt,
                        cre2_anchor_t anchor);
    cre2_decl void cre2_set_delete(cre2_set *set);
    cre2_decl int cre2_set_add(cre2_set *set, const char *pattern,
              size_t pattern_len, char *error, size_t error_len);
    cre2_decl int cre2_set_add_simple(cre2_set *set, const char *pattern);
    cre2_decl int cre2_set_compile(cre2_set *set);
    cre2_decl size_t cre2_set_match(cre2_set *set,
                     const char *text, size_t text_len,
                     int *match, size_t match_len);
  \end{ccode}
\end{minipage}

正则表达式集合实例如代码\ref{code-cre2-set-match}所示。

\cvfile[label=code-cre2-set-match]{正则表达式集合匹配}%
  {google-cre2/codes/tests/08test-set.c}

\section{命名迭代器}

可以通过分配编译后的正则表达式以获得正则表达式分组信息及其迭代器，相关函数原型为：

\begin{minipage}{0.90\textwidth}
  \begin{ccode}
    int cre2_num_capturing_groups(const cre2_regexp_t * rex);
    int cre2_find_named_capturing_groups(const cre2_regexp_t * rex,
                                         const char * name);
    cre2_named_groups_iter_t * cre2_named_groups_iter_new(
                               const cre2_regexp_t * re);
    void cre2_named_groups_iter_delete(cre2_named_groups_iter_t * iter);
    bool cre2_named_groups_iter_next(cre2_named_groups_iter_t * iter,
                                     const char ** namep, int * indexp);
  \end{ccode}
\end{minipage}

迭代器使用实例如代码\ref{code-cre2-iter}所示。

\cvfile[label=code-cre2-iter]{命名迭代器}%
  {google-cre2/codes/tests/10test-capture-names-iter.c}

\section{正则选项}

如果需要处理正则选项，可以使用正则选项对象处理函数，如代码\ref{code-cre2-opts}所示。

\cvfile[label=code-cre2-opts]{正则选项}{google-cre2/codes/tests/11test-options.c}

\section{编译内存分配}

如果需要管理编译内存分配，可以参考代码\ref{code-cre2-rexalloc}。

\cvfile[label=code-cre2-rexalloc]{编译内存分配}%
  {google-cre2/codes/tests/12test-rex-alloc.c}

\section{其它接口}

其它与匹配相关的函数，如代码\ref{code-cre2-misc-match}所示。

\cvfile[label=code-cre2-misc-match]{其它接口}{google-cre2/codes/tests/09test-misc.c}

\section{查看版本}

如果需要查看CRE2库版本，可以参考代码\ref{code-cre2-version}。

\cvfile[label=code-cre2-version]{编译内存分配}{google-cre2/codes/tests/13test-version.c}

有关CRE2的类型定义和接口详情，可参阅附录\ref{cre2-app-interface}。
